﻿using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using ProbeGUI.BingAPI;
using System.Xml;
using System.Collections;
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace ProbeGUI
{
    class BingProbe
    {
        // NOTE: You must get your own API key from Microsoft at http://www.bing.com/developers/createapp.aspx
        private static string AppID = "7798127B02DA23455A71FB5165FEA82108B69EDB";
        private static string BingEndPoint = "http://api.bing.net:80/soap.asmx";

        Hashtable siteCollection;
        BingPortTypeClient bing = null;

        public BingProbe()
        {
            siteCollection = new Hashtable();
            bing = new BingPortTypeClient(
                new BasicHttpBinding(), new EndpointAddress(BingEndPoint));
        }

        public string ListSites(string ipAddr)
        {
            StringBuilder result = new StringBuilder("");
            IPAddress[] addrs = new IPAddress[0];

            try
            {
                addrs = Dns.GetHostAddresses(ipAddr);
            }
            catch (SocketException)
            {
                return result.ToString();
            }

            foreach (IPAddress addr in addrs)
            {
                result.AppendFormat("\nAddress = {0}\n", addr);
                uint offSet = 0;
                SearchResponse response = ProbeServer(addr.ToString(), offSet);
                while (offSet < response.Web.Total)
                {
                    // Display the Web results.
                    foreach (WebResult wr in response.Web.Results)
                    {
                        Uri url = new Uri(wr.Url);

                        SiteInfo info = new SiteInfo();
                        info.Title = wr.Title;
                        info.Description = wr.Description;
                        info.DisplayURL = url.Host;

                        if (!siteCollection.ContainsKey(info.DisplayURL))
                        {
                            siteCollection.Add(info.DisplayURL, info);
                        }
                    }

                    offSet += 50;
                    response = ProbeServer(addr.ToString(), offSet);
                }

                ShowSites(ref result);
            }

            return result.ToString();
        }

        SearchResponse ProbeServer(string ipAddr, uint offSet)
        {
            return bing.Search(BuildProbeRequest(ipAddr, offSet));
        }

        private SearchRequest BuildProbeRequest(string ipAddr, uint offSet)
        {
            ProbeGUI.BingAPI.SearchRequest request = 
                new ProbeGUI.BingAPI.SearchRequest();

            // Common request fields (required)
            request.AppId = AppID;
            request.Query = "ip:" + ipAddr;
            request.Sources = new SourceType[] { SourceType.Web };

            // Common request fields (optional)
            request.Version = "2.0";
            request.Market = "en-us";
            request.Adult = AdultOption.Off;
            request.AdultSpecified = true;
            request.Options = new SearchOption[]
            {
                SearchOption.EnableHighlighting
            };

            request.Web = new ProbeGUI.BingAPI.WebRequest();
            request.Web.Count = 50;
            request.Web.CountSpecified = true;
            request.Web.Offset = offSet;
            request.Web.OffsetSpecified = true;
            request.Web.Options = new WebSearchOption[]
            {
                WebSearchOption.DisableQueryAlterations
            };

            return request;
        }
        
        void DisplayErrors(XmlNode errorDetails)
        {
            // Add the default namespace to the namespace manager.
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(
                errorDetails.OwnerDocument.NameTable);
            
            nsmgr.AddNamespace(
                "api",
                "http://schemas.microsoft.com/LiveSearch/2008/03/Search");

            XmlNodeList errors = errorDetails.SelectNodes(
                "./api:Errors/api:Error",
                nsmgr);

            if (errors != null)
            {
                // Iterate over the list of errors and display error details.
                Console.WriteLine("Errors:");
                Console.WriteLine();
                foreach (XmlNode error in errors)
                {
                    foreach (XmlNode detail in error.ChildNodes)
                    {
                        Console.WriteLine(detail.Name + ": " + detail.InnerText);
                    }

                    Console.WriteLine();
                }
            }
        }

        private void ShowSites(ref StringBuilder results)
        {
            foreach (SiteInfo info in siteCollection.Values)
            {
                results.Append(" " + info.DisplayURL + "\n");
            }
        }
    }

    public class SiteInfo
    {
        public string Title { get; set; }
        public string Description { get; set; }
        public string DisplayURL { get; set; }
    }
}
